home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / CONTRIB / GEARS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  12.7 KB  |  570 lines

  1. #include <stdlib.h>
  2. #include <GL/glut.h>
  3.  
  4. #include <math.h>
  5. #ifndef _WIN32
  6. #include <unistd.h>
  7. #endif
  8. /* Some <math.h> files do not define M_PI... */
  9. #ifndef M_PI
  10. #define M_PI 3.14159265358979323846
  11. #endif
  12. #include <sys/types.h>
  13. #include <stdio.h>
  14.  
  15. /* For portability... */
  16. #undef fcos
  17. #undef fsin
  18. #undef fsqrt
  19. #define fcos  cos
  20. #define fsin  sin
  21. #define fsqrt sqrt
  22.  
  23. static double d_near = 1.0;
  24. static double d_far = 2000;
  25. static int poo = 0;
  26.  
  27. typedef struct {
  28.   float rad, wid;
  29. } Profile;
  30.  
  31. void flat_face(float ir, float or, float wd);
  32. void draw_inside(float w1, float w2, float rad);
  33. void draw_outside(float w1, float w2, float rad);
  34. void tooth_side(int nt, float ir, float or, float tp, float tip, float wd);
  35.  
  36. int circle_subdiv;
  37.  
  38. int mode = GLUT_DOUBLE;
  39.  
  40. void
  41. gear(int nt, float wd, float ir, float or, float tp, float tip, int ns, Profile * ip)
  42. {
  43.   /**
  44.    * nt - number of teeth 
  45.    * wd - width of gear at teeth
  46.    * ir - inside radius absolute scale
  47.    * or - radius at outside of wheel (tip of tooth) ratio of ir
  48.    * tp - ratio of tooth in slice of circle (0..1] (1 = teeth are touching at base)
  49.    * tip - ratio of tip of tooth (0..tp] (cant be wider that base of tooth)
  50.    * ns - number of elements in wheel width profile
  51.    * *ip - list of float pairs {start radius, width, ...} (width is ratio to wd)
  52.    *
  53.    */
  54.  
  55.   /* gear lying on xy plane, z for width. all normals calulated 
  56.      (normalized) */
  57.  
  58.   float prev;
  59.   int k, t;
  60.  
  61.   /* estimat # times to divide circle */
  62.   if (nt <= 0)
  63.     circle_subdiv = 64;
  64.   else {
  65.     /* lowest multiple of number of teeth */
  66.     circle_subdiv = nt;
  67.     while (circle_subdiv < 64)
  68.       circle_subdiv += nt;
  69.   }
  70.  
  71.   /* --- draw wheel face --- */
  72.  
  73.   /* draw horzontal, vertical faces for each section. if first
  74.      section radius not zero, use wd for 0.. first if ns == 0
  75.      use wd for whole face. last width used to edge.  */
  76.  
  77.   if (ns <= 0) {
  78.     flat_face(0.0, ir, wd);
  79.   } else {
  80.     /* draw first flat_face, then continue in loop */
  81.     if (ip[0].rad > 0.0) {
  82.       flat_face(0.0, ip[0].rad * ir, wd);
  83.       prev = wd;
  84.       t = 0;
  85.     } else {
  86.       flat_face(0.0, ip[1].rad * ir, ip[0].wid * wd);
  87.       prev = ip[0].wid;
  88.       t = 1;
  89.     }
  90.     for (k = t; k < ns; k++) {
  91.       if (prev < ip[k].wid) {
  92.         draw_inside(prev * wd, ip[k].wid * wd, ip[k].rad * ir);
  93.       } else {
  94.         draw_outside(prev * wd, ip[k].wid * wd, ip[k].rad * ir);
  95.       }
  96.       prev = ip[k].wid;
  97.       /* - draw to edge of wheel, add final face if needed - */
  98.       if (k == ns - 1) {
  99.         flat_face(ip[k].rad * ir, ir, ip[k].wid * wd);
  100.  
  101.         /* now draw side to match tooth rim */
  102.         if (ip[k].wid < 1.0) {
  103.           draw_inside(ip[k].wid * wd, wd, ir);
  104.         } else {
  105.           draw_outside(ip[k].wid * wd, wd, ir);
  106.         }
  107.       } else {
  108.         flat_face(ip[k].rad * ir, ip[k + 1].rad * ir, ip[k].wid * wd);
  109.       }
  110.     }
  111.   }
  112.  
  113.   /* --- tooth side faces --- */
  114.   tooth_side(nt, ir, or, tp, tip, wd);
  115.  
  116.   /* --- tooth hill surface --- */
  117. }
  118.  
  119. void 
  120. tooth_side(int nt, float ir, float or, float tp, float tip, float wd)
  121. {
  122.  
  123.   float i;
  124.   float end = 2.0 * M_PI / nt;
  125.   float x[6], y[6];
  126.   float s[3], c[3];
  127.  
  128.   or = or * ir;         /* or is really a ratio of ir */
  129.   for (i = 0; i < 2.0 * M_PI - end / 4.0; i += end) {
  130.  
  131.     c[0] = fcos(i);
  132.     s[0] = fsin(i);
  133.     c[1] = fcos(i + end * (0.5 - tip / 2));
  134.     s[1] = fsin(i + end * (0.5 - tip / 2));
  135.     c[2] = fcos(i + end * (0.5 + tp / 2));
  136.     s[2] = fsin(i + end * (0.5 + tp / 2));
  137.  
  138.     x[0] = ir * c[0];
  139.     y[0] = ir * s[0];
  140.     x[5] = ir * fcos(i + end);
  141.     y[5] = ir * fsin(i + end);
  142.     /* ---treat veritices 1,4 special to match strait edge of
  143.        face */
  144.     x[1] = x[0] + (x[5] - x[0]) * (0.5 - tp / 2);
  145.     y[1] = y[0] + (y[5] - y[0]) * (0.5 - tp / 2);
  146.     x[4] = x[0] + (x[5] - x[0]) * (0.5 + tp / 2);
  147.     y[4] = y[0] + (y[5] - y[0]) * (0.5 + tp / 2);
  148.     x[2] = or * fcos(i + end * (0.5 - tip / 2));
  149.     y[2] = or * fsin(i + end * (0.5 - tip / 2));
  150.     x[3] = or * fcos(i + end * (0.5 + tip / 2));
  151.     y[3] = or * fsin(i + end * (0.5 + tip / 2));
  152.  
  153.     /* draw face trapezoids as 2 tmesh */
  154.     glNormal3f(0.0, 0.0, 1.0);
  155.     glBegin(GL_TRIANGLE_STRIP);
  156.     glVertex3f(x[2], y[2], wd / 2);
  157.     glVertex3f(x[1], y[1], wd / 2);
  158.     glVertex3f(x[3], y[3], wd / 2);
  159.     glVertex3f(x[4], y[4], wd / 2);
  160.     glEnd();
  161.  
  162.     glNormal3f(0.0, 0.0, -1.0);
  163.     glBegin(GL_TRIANGLE_STRIP);
  164.     glVertex3f(x[2], y[2], -wd / 2);
  165.     glVertex3f(x[1], y[1], -wd / 2);
  166.     glVertex3f(x[3], y[3], -wd / 2);
  167.     glVertex3f(x[4], y[4], -wd / 2);
  168.     glEnd();
  169.  
  170.     /* draw inside rim pieces */
  171.     glNormal3f(c[0], s[0], 0.0);
  172.     glBegin(GL_TRIANGLE_STRIP);
  173.     glVertex3f(x[0], y[0], -wd / 2);
  174.     glVertex3f(x[1], y[1], -wd / 2);
  175.     glVertex3f(x[0], y[0], wd / 2);
  176.     glVertex3f(x[1], y[1], wd / 2);
  177.     glEnd();
  178.  
  179.     /* draw up hill side */
  180.     {
  181.       float a, b, n;
  182.       /* calculate normal of face */
  183.       a = x[2] - x[1];
  184.       b = y[2] - y[1];
  185.       n = 1.0 / fsqrt(a * a + b * b);
  186.       a = a * n;
  187.       b = b * n;
  188.       glNormal3f(b, -a, 0.0);
  189.     }
  190.     glBegin(GL_TRIANGLE_STRIP);
  191.     glVertex3f(x[1], y[1], -wd / 2);
  192.     glVertex3f(x[2], y[2], -wd / 2);
  193.     glVertex3f(x[1], y[1], wd / 2);
  194.     glVertex3f(x[2], y[2], wd / 2);
  195.     glEnd();
  196.     /* draw top of hill */
  197.     glNormal3f(c[1], s[1], 0.0);
  198.     glBegin(GL_TRIANGLE_STRIP);
  199.     glVertex3f(x[2], y[2], -wd / 2);
  200.     glVertex3f(x[3], y[3], -wd / 2);
  201.     glVertex3f(x[2], y[2], wd / 2);
  202.     glVertex3f(x[3], y[3], wd / 2);
  203.     glEnd();
  204.  
  205.     /* draw down hill side */
  206.     {
  207.       float a, b, c;
  208.       /* calculate normal of face */
  209.       a = x[4] - x[3];
  210.       b = y[4] - y[3];
  211.       c = 1.0 / fsqrt(a * a + b * b);
  212.       a = a * c;
  213.       b = b * c;
  214.       glNormal3f(b, -a, 0.0);
  215.     }
  216.     glBegin(GL_TRIANGLE_STRIP);
  217.     glVertex3f(x[3], y[3], -wd / 2);
  218.     glVertex3f(x[4], y[4], -wd / 2);
  219.     glVertex3f(x[3], y[3], wd / 2);
  220.     glVertex3f(x[4], y[4], wd / 2);
  221.     glEnd();
  222.     /* inside rim part */
  223.     glNormal3f(c[2], s[2], 0.0);
  224.     glBegin(GL_TRIANGLE_STRIP);
  225.     glVertex3f(x[4], y[4], -wd / 2);
  226.     glVertex3f(x[5], y[5], -wd / 2);
  227.     glVertex3f(x[4], y[4], wd / 2);
  228.     glVertex3f(x[5], y[5], wd / 2);
  229.     glEnd();
  230.   }
  231. }
  232.  
  233. void 
  234. flat_face(float ir, float or, float wd)
  235. {
  236.  
  237.   int i;
  238.   float w;
  239.  
  240.   /* draw each face (top & bottom ) * */
  241.   if (poo)
  242.     printf("Face  : %f..%f wid=%f\n", ir, or, wd);
  243.   if (wd == 0.0)
  244.     return;
  245.   for (w = wd / 2; w > -wd; w -= wd) {
  246.     if (w > 0.0)
  247.       glNormal3f(0.0, 0.0, 1.0);
  248.     else
  249.       glNormal3f(0.0, 0.0, -1.0);
  250.  
  251.     if (ir == 0.0) {
  252.       /* draw as t-fan */
  253.       glBegin(GL_TRIANGLE_FAN);
  254.       glVertex3f(0.0, 0.0, w);  /* center */
  255.       glVertex3f(or, 0.0, w);
  256.       for (i = 1; i < circle_subdiv; i++) {
  257.         glVertex3f(fcos(2.0 * M_PI * i / circle_subdiv) * or,
  258.           fsin(2.0 * M_PI * i / circle_subdiv) * or,
  259.           w);
  260.       }
  261.       glVertex3f(or, 0.0, w);
  262.       glEnd();
  263.     } else {
  264.       /* draw as tmesh */
  265.       glBegin(GL_TRIANGLE_STRIP);
  266.       glVertex3f(or, 0.0, w);
  267.       glVertex3f(ir, 0.0, w);
  268.       for (i = 1; i < circle_subdiv; i++) {
  269.         glVertex3f(fcos(2.0 * M_PI * i / circle_subdiv) * or,
  270.           fsin(2.0 * M_PI * i / circle_subdiv) * or,
  271.           w);
  272.         glVertex3f(fcos(2.0 * M_PI * i / circle_subdiv) * ir,
  273.           fsin(2.0 * M_PI * i / circle_subdiv) * ir,
  274.           w);
  275.       }
  276.       glVertex3f(or, 0.0, w);
  277.       glVertex3f(ir, 0.0, w);
  278.       glEnd();
  279.  
  280.     }
  281.   }
  282. }
  283.  
  284. void 
  285. draw_inside(float w1, float w2, float rad)
  286. {
  287.  
  288.   int i, j;
  289.   float c, s;
  290.   if (poo)
  291.     printf("Inside: wid=%f..%f rad=%f\n", w1, w2, rad);
  292.   if (w1 == w2)
  293.     return;
  294.  
  295.   w1 = w1 / 2;
  296.   w2 = w2 / 2;
  297.   for (j = 0; j < 2; j++) {
  298.     if (j == 1) {
  299.       w1 = -w1;
  300.       w2 = -w2;
  301.     }
  302.     glBegin(GL_TRIANGLE_STRIP);
  303.     glNormal3f(-1.0, 0.0, 0.0);
  304.     glVertex3f(rad, 0.0, w1);
  305.     glVertex3f(rad, 0.0, w2);
  306.     for (i = 1; i < circle_subdiv; i++) {
  307.       c = fcos(2.0 * M_PI * i / circle_subdiv);
  308.       s = fsin(2.0 * M_PI * i / circle_subdiv);
  309.       glNormal3f(-c, -s, 0.0);
  310.       glVertex3f(c * rad,
  311.         s * rad,
  312.         w1);
  313.       glVertex3f(c * rad,
  314.         s * rad,
  315.         w2);
  316.     }
  317.     glNormal3f(-1.0, 0.0, 0.0);
  318.     glVertex3f(rad, 0.0, w1);
  319.     glVertex3f(rad, 0.0, w2);
  320.     glEnd();
  321.   }
  322. }
  323.  
  324. void 
  325. draw_outside(float w1, float w2, float rad)
  326. {
  327.  
  328.   int i, j;
  329.   float c, s;
  330.   if (poo)
  331.     printf("Outsid: wid=%f..%f rad=%f\n", w1, w2, rad);
  332.   if (w1 == w2)
  333.     return;
  334.  
  335.   w1 = w1 / 2;
  336.   w2 = w2 / 2;
  337.   for (j = 0; j < 2; j++) {
  338.     if (j == 1) {
  339.       w1 = -w1;
  340.       w2 = -w2;
  341.     }
  342.     glBegin(GL_TRIANGLE_STRIP);
  343.     glNormal3f(1.0, 0.0, 0.0);
  344.     glVertex3f(rad, 0.0, w1);
  345.     glVertex3f(rad, 0.0, w2);
  346.     for (i = 1; i < circle_subdiv; i++) {
  347.       c = fcos(2.0 * M_PI * i / circle_subdiv);
  348.       s = fsin(2.0 * M_PI * i / circle_subdiv);
  349.       glNormal3f(c, s, 0.0);
  350.       glVertex3f(c * rad,
  351.         s * rad,
  352.         w1);
  353.       glVertex3f(c * rad,
  354.         s * rad,
  355.         w2);
  356.     }
  357.     glNormal3f(1.0, 0.0, 0.0);
  358.     glVertex3f(rad, 0.0, w1);
  359.     glVertex3f(rad, 0.0, w2);
  360.     glEnd();
  361.   }
  362. }
  363.  
  364. Profile gear_profile[] =
  365. {0.000, 0.0,
  366.   0.300, 7.0,
  367.   0.340, 0.4,
  368.   0.550, 0.64,
  369.   0.600, 0.4,
  370.   0.950, 1.0
  371. };
  372.  
  373. float a1 = 27.0;
  374. float a2 = 67.0;
  375. float a3 = 47.0;
  376. float a4 = 87.0;
  377. float i1 = 1.2;
  378. float i2 = 3.1;
  379. float i3 = 2.3;
  380. float i4 = 1.1;
  381. void
  382. oneFrame(void)
  383. {
  384.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  385.  
  386.   glPushMatrix();
  387.   glTranslatef(0.0, 0.0, -4.0);
  388.   glRotatef(a3, 1.0, 1.0, 1.0);
  389.   glRotatef(a4, 0.0, 0.0, -1.0);
  390.   glTranslatef(0.14, 0.2, 0.0);
  391.   gear(76,
  392.     0.4, 2.0, 1.1,
  393.     0.4, 0.04,
  394.     sizeof(gear_profile) / sizeof(Profile), gear_profile);
  395.   glPopMatrix();
  396.  
  397.   glPushMatrix();
  398.   glTranslatef(0.1, 0.2, -3.8);
  399.   glRotatef(a2, -4.0, 2.0, -1.0);
  400.   glRotatef(a1, 1.0, -3.0, 1.0);
  401.   glTranslatef(0.0, -0.2, 0.0);
  402.   gear(36,
  403.     0.4, 2.0, 1.1,
  404.     0.7, 0.2,
  405.     sizeof(gear_profile) / sizeof(Profile), gear_profile);
  406.   glPopMatrix();
  407.  
  408.   a1 += i1;
  409.   if (a1 > 360.0)
  410.     a1 -= 360.0;
  411.   if (a1 < 0.0)
  412.     a1 -= 360.0;
  413.   a2 += i2;
  414.   if (a2 > 360.0)
  415.     a2 -= 360.0;
  416.   if (a2 < 0.0)
  417.     a2 -= 360.0;
  418.   a3 += i3;
  419.   if (a3 > 360.0)
  420.     a3 -= 360.0;
  421.   if (a3 < 0.0)
  422.     a3 -= 360.0;
  423.   a4 += i4;
  424.   if (a4 > 360.0)
  425.     a4 -= 360.0;
  426.   if (a4 < 0.0)
  427.     a4 -= 360.0;
  428.   if (mode == GLUT_SINGLE) {
  429.     glFlush();
  430.   } else {
  431.     glutSwapBuffers();
  432.   }
  433. }
  434.  
  435. void
  436. display(void)
  437. {
  438.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  439. }
  440.  
  441. void
  442. myReshape(int w, int h)
  443. {
  444.   glViewport(0, 0, w, h);
  445.   glMatrixMode(GL_PROJECTION);
  446.   glLoadIdentity();
  447.   glFrustum(-1.0, 1.0, -1.0, 1.0, d_near, d_far);
  448.   /**
  449.     use perspective instead:
  450.  
  451.     if (w <= h){
  452.         glOrtho( 0.0, 1.0,
  453.                  0.0, 1.0 * (GLfloat) h / (GLfloat) w,
  454.                 -16.0, 4.0);
  455.     }else{
  456.         glOrtho( 0.0, 1.0 * (GLfloat) w / (GLfloat) h,
  457.                  0.0, 1.0,
  458.                 -16.0, 4.0);
  459.     }
  460.    */
  461.   glMatrixMode(GL_MODELVIEW);
  462.   glLoadIdentity();
  463.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  464. }
  465.  
  466. void
  467. visibility(int status)
  468. {
  469.   if (status == GLUT_VISIBLE) {
  470.     glutIdleFunc(oneFrame);
  471.   } else {
  472.     glutIdleFunc(NULL);
  473.   }
  474.  
  475. }
  476.  
  477. void
  478. myinit(void)
  479. {
  480.   float f[20];
  481.   glClearColor(0.0, 0.0, 0.0, 0.0);
  482.   myReshape(640, 480);
  483.   /* glShadeModel(GL_FLAT); */
  484.   glEnable(GL_DEPTH_TEST);
  485.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  486.  
  487.   glEnable(GL_LIGHTING);
  488.  
  489.   glLightf(GL_LIGHT0, GL_SHININESS, 1.0);
  490.   f[0] = 1.3;
  491.   f[1] = 1.3;
  492.   f[2] = -3.3;
  493.   f[3] = 1.0;
  494.   glLightfv(GL_LIGHT0, GL_POSITION, f);
  495.   f[0] = 0.8;
  496.   f[1] = 1.0;
  497.   f[2] = 0.83;
  498.   f[3] = 1.0;
  499.   glLightfv(GL_LIGHT0, GL_SPECULAR, f);
  500.   glLightfv(GL_LIGHT0, GL_DIFFUSE, f);
  501.   glEnable(GL_LIGHT0);
  502.  
  503.   glLightf(GL_LIGHT1, GL_SHININESS, 1.0);
  504.   f[0] = -2.3;
  505.   f[1] = 0.3;
  506.   f[2] = -7.3;
  507.   f[3] = 1.0;
  508.   glLightfv(GL_LIGHT1, GL_POSITION, f);
  509.   f[0] = 1.0;
  510.   f[1] = 0.8;
  511.   f[2] = 0.93;
  512.   f[3] = 1.0;
  513.   glLightfv(GL_LIGHT1, GL_SPECULAR, f);
  514.   glLightfv(GL_LIGHT1, GL_DIFFUSE, f);
  515.   glEnable(GL_LIGHT1);
  516.  
  517.   /* gear material */
  518.   f[0] = 0.1;
  519.   f[1] = 0.15;
  520.   f[2] = 0.2;
  521.   f[3] = 1.0;
  522.   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, f);
  523.  
  524.   f[0] = 0.9;
  525.   f[1] = 0.3;
  526.   f[2] = 0.3;
  527.   f[3] = 1.0;
  528.   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, f);
  529.  
  530.   f[0] = 0.4;
  531.   f[1] = 0.9;
  532.   f[2] = 0.6;
  533.   f[3] = 1.0;
  534.   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, f);
  535.  
  536.   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 4);
  537. }
  538.  
  539. /* ARGSUSED1 */
  540. void
  541. keys(unsigned char c, int x, int y)
  542. {
  543.  
  544.   if (c == 0x1b)
  545.     exit(0);            /* escape */
  546. }
  547.  
  548. int
  549. main(int argc, char **argv)
  550. {
  551.   glutInit(&argc, argv);
  552.  
  553.   if (argc > 1)
  554.     mode = GLUT_SINGLE;
  555.   glutInitDisplayMode(mode | GLUT_RGB | GLUT_DEPTH);
  556.   glutInitWindowPosition(100, 100);
  557.   glutInitWindowSize(640, 480);
  558.   glutCreateWindow(argv[0]);
  559.  
  560.   myinit();
  561.   glutReshapeFunc(myReshape);
  562.   glutDisplayFunc(display);
  563.   glutKeyboardFunc(keys);
  564.   glutVisibilityFunc(visibility);
  565.   glutPostRedisplay();
  566.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  567.   glutMainLoop();
  568.   return 0;             /* ANSI C requires main to return int. */
  569. }
  570.